require "lfs"
require "unity"
require "luaMPI"
----------------------------------------------------------------------------
--初始化参数
local MPIModel={
	num_threads = 24;                     -- 计算线程数：单节点的核数
	name = "New Model";
	max_steps  = 30000;
	max_convergency = -35;
	stride = 50;
	
	boundary = { xm=UPML; };
	num_pml = 6;
	units = { freq = GHz; dim = mm; time = s; };
	mesh_freq = 12;
	name = "unname";
	save2file = false;
	camera = "3377.21 -3356.18 2213.26 0.4964 0.205616 0.322752 0.779192";
	console_mode = 'true';
};
-----------------------------------------------------------------------------

-----------------------------------------------------------------------------
--创建表和创建元表
function MPIModel:new (o)
	o = o or {};
	self.__index = self;
	setmetatable(o,self)
	return o;
end
-----------------------------------------------------------------------------

-----------------------------------------------------------------------------
--初始化
function MPIModel:init ()
	collectgarbage()
	print("collectgarbage");
	collectgarbage()
	Geometry.clear_all();
end
-----------------------------------------------------------------------------


function MPIModel:set_boundary()
	
	Geometry.Boundaries.boundary( xm , self.boundary.xm or UPML );
	Geometry.Boundaries.boundary( ym , self.boundary.ym or UPML );
	Geometry.Boundaries.boundary( zm , self.boundary.zm or UPML );
	Geometry.Boundaries.boundary( xp , self.boundary.xp or UPML );
	Geometry.Boundaries.boundary( yp , self.boundary.yp or UPML );
	Geometry.Boundaries.boundary( zp , self.boundary.zp or UPML );
	Geometry.Boundaries.num_pml( self.num_pml );

	--print( "boundary conditions","xm:"..bc_to_string(Geometry.Boundaries.boundary(xm)),"ym:"..bc_to_string(Geometry.Boundaries.boundary(ym)),"zm:"..bc_to_string(Geometry.Boundaries.boundary(zm)) );
	--print( "boundary conditions","xp:"..bc_to_string(Geometry.Boundaries.boundary(xp)),"yp:"..bc_to_string(Geometry.Boundaries.boundary(yp)),"zp:"..bc_to_string(Geometry.Boundaries.boundary(zp)) );
end



function MPIModel:set_units()
	Geometry.ref_units( self.units.dim or mm, self.units.freq or GHz,self.units.time or s) --units
	print( "set dimention units:", self.units.dim)
	  -- print( "set dimention units:",units_dim_to_string(geo:ref_units_dim()))
	 -- print( "set frequency units:",units_freq_to_string(geo:ref_units_freq()))
end

function MPIModel:set_mesh_freq()
	assert( self.mesh_freq, " 需要设置剖分参考频率: mesh_freq " )
	Geometry.Mesh.mesh_freq( self.mesh_freq )
	print( "set mesh frequency:", Geometry.Mesh.mesh_freq().."[in ref units]" )
end

function MPIModel:set_threads()
	assert( self.num_threads, " 需要设置线程数量: num_threads " )
	Geometry.Solver.threads( self.num_threads )
	print( "set number of theads:",Geometry.Solver.threads() )
end


function MPIModel:create_grabber(  )
	print( "create grabber")	
	 local cm = Geometry.CGLColorMap:new("Jet")
	 local  probe = Geometry.TransientFieldsGrabber:new();
	 probe :name("Grabber-xy("..self.name..")");
	 probe :camera(self.camera)
	  probe :save2file(self.save2file);
	 probe :frame_delay(20);
	 probe :size(600,450);
	 probe :add_slice(cm,scalar_e,xy,0,2,false)
	 -- probe :add_slice(cm,ez,yz,0,2)
	  -- probe :is_fill(false);
	 -- probe:fields_types(ez,hx)
	 probe :stride(20);
	 Geometry.AddTransientFieldsGrabber(probe)
	----------------------------
end
function MPIModel:create_source()
end

-----------------------------------------------------------------------------
--运行
function MPIModel:perspective_view ()
	-- print('perspective')
	if self.console_mode == false then
		local QGallop = require"QGMainWindow"
		if QGallop~=nil and QGallop.getMainWindow then
			local mw = QGallop.getMainWindow();
			if mw~=nil then
				require"Q3DViewer"
				local view = mw:get3DView();
				if view~=nil then
					view:showEntireScene();
					view:perspective();
				end
			end
		end
	end
end
-----------------------------------------------------------------------------

-----------------------------------------------------------------------------
--前处理
function MPIModel:pre_run ()
	print ( "save geometry" )	
	Geometry.SaveGeometry( self.name..".gap") 
end
-----------------------------------------------------------------------------

-----------------------------------------------------------------------------
--运行
function MPIModel:run ()
	self:perspective_view()	
	print( "run model:" .. self.name )
	
	self:pre_run ()

	Geometry.Solver.pre_calculate()	
	for ii=1,self.max_steps/self.stride do
		if( Geometry.Solver.convergence_coefficient()<self.max_convergency ) then
			break;
		end
		Geometry.Solver.steps( self.stride )
	end
	print ( "iteration finished..." )
	Geometry.Solver.stop()
	print ( "stop solver, and start post calculation ..." )
	self:post_run()
	print( "calculation finished:" .. self.name )
end
-----------------------------------------------------------------------------


-----------------------------------------------------------------------------
--后处理
function MPIModel:post_run ()
	print( "update probe" )
	-- Geometry.find_probe("fbox") :update()
	Geometry.find_probe("fbox") :save( self.name..".txt", "dBsm" )
	Geometry.SaveGeometry( self.name..".gap")
end
-----------------------------------------------------------------------------

return MPIModel;
